#ifndef EASYASIO_NET_UTILS_HPP
#define EASYASIO_NET_UTILS_HPP

#include <string>
#include <map>

namespace easyasio {
namespace base {

class Timer
{
public: 
    Timer()
    { reset(); }

    long long elapsed()
    {
        std::chrono::milliseconds end = 
            std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::steady_clock::now().time_since_epoch());
        return end.count() - start_.count();
    }

    void reset()
    {
        start_ = 
            std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::steady_clock::now().time_since_epoch());
    }
private:
    std::chrono::milliseconds start_;
};

class noncopyable
{
public:
	noncopyable(){}
	~noncopyable(){}

	noncopyable(const noncopyable&) = delete;
	noncopyable operator= (const noncopyable&) = delete;
	noncopyable(noncopyable&&) = delete;
	noncopyable operator= (noncopyable&&) = delete;
};

class copyable { };

class CountDownLatch
{
public:
    explicit CountDownLatch(int count)
        :count_(count)
    {
        assert(count_ > 0);
    }

    void wait()
    {
        std::unique_lock<std::mutex> lock(mutex_);
        while (count_ != 0)
        {
            cond_.wait(lock);
        }
    }

    bool waitFor(std::chrono::milliseconds msecs)
    {
        std::unique_lock<std::mutex> lock(mutex_);
        while (count_ != 0)
        {
            std::cv_status ret = cond_.wait_for(lock, msecs);
            if (ret == std::cv_status::timeout)
                break;
        }

        return count_ == 0;
    }

    void countDown()
    {
        std::unique_lock<std::mutex> lock(mutex_);
        count_--;
        cond_.notify_all();
    }

    void countDown(const std::string& resultname, bool result)
    {
        std::unique_lock<std::mutex> lock(mutex_);
        count_--;
        results_[resultname] = result;
        cond_.notify_all();
    }

    int getCount() const
    {
        std::unique_lock<std::mutex> lock(mutex_);
        return count_;
    }

    bool getResult(const std::string& resultname)
    {
        std::map<std::string, bool>::iterator iter = 
            results_.find(resultname);
        if (iter == results_.end())
            return false;
        return iter->second;
    }

private:
    mutable std::mutex mutex_;
    int count_;
    std::map<std::string, bool> results_;
    std::condition_variable cond_;
};

}//net
}//easyasio


#endif//EASYASIO_NET_UTILS_HPP